/*
 * Copyright 2002-2019 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.aop.framework.autoproxy;

import java.util.List;

import org.springframework.aop.Advisor;
import org.springframework.aop.TargetSource;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

/**
 * Generic auto proxy creator that builds AOP proxies for specific beans
 * based on detected Advisors for each bean.
 *
 * <p>Subclasses may override the {@link #findCandidateAdvisors()} method to
 * return a custom list of Advisors applying to any object. Subclasses can
 * also override the inherited {@link #shouldSkip} method to exclude certain
 * objects from auto-proxying.
 *
 * <p>Advisors or advices requiring ordering should implement the
 * {@link org.springframework.core.Ordered} interface. This class sorts
 * Advisors by Ordered order value. Advisors that don't implement the
 * Ordered interface will be considered as unordered; they will appear
 * at the end of the advisor chain in undefined order.
 *
 * @author Rod Johnson
 * @author Juergen Hoeller
 * @see #findCandidateAdvisors
 */
@SuppressWarnings("serial")
public abstract class AbstractAdvisorAutoProxyCreator extends AbstractAutoProxyCreator {

	@Nullable
	private BeanFactoryAdvisorRetrievalHelper advisorRetrievalHelper;


	@Override
	public void setBeanFactory(BeanFactory beanFactory) {
		super.setBeanFactory(beanFactory);
		if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
			throw new IllegalArgumentException(
					"AdvisorAutoProxyCreator requires a ConfigurableListableBeanFactory: " + beanFactory);
		}
		initBeanFactory((ConfigurableListableBeanFactory) beanFactory);
	}

	protected void initBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		this.advisorRetrievalHelper = new BeanFactoryAdvisorRetrievalHelperAdapter(beanFactory);
	}


	@Override
	@Nullable
	protected Object[] getAdvicesAndAdvisorsForBean(
			Class<?> beanClass, String beanName, @Nullable TargetSource targetSource) {

		List<Advisor> advisors = findEligibleAdvisors(beanClass, beanName);
		if (advisors.isEmpty()) {
			return DO_NOT_PROXY;
		}
		return advisors.toArray();
	}

	/**
	 * 查找适用于指定 Bean 类的所有合格增强器(Advisor)，用于自动代理创建。
	 * 该方法实现了 AOP 增强器的发现、筛选、扩展和排序的完整流程，
	 * 是 Spring AOP 自动代理机制的核心步骤之一。
	 *
	 * <p>执行流程：
	 * <ol>
	 *   <li>通过 findCandidateAdvisors 获取所有候选增强器</li>
	 *   <li>通过 findAdvisorsThatCanApply 筛选出真正适用于目标 Bean 的增强器</li>
	 *   <li>调用 extendAdvisors 方法对筛选结果进行扩展（如添加基础设施增强器）</li>
	 *   <li>对最终合格的增强器列表进行排序，确保按正确顺序执行</li>
	 * </ol>
	 *
	 * <p>增强器筛选逻辑：
	 * <ul>
	 *   <li>候选增强器可能来自多个来源（如 BeanFactory、注解扫描等）</li>
	 *   <li>筛选过程会检查增强器的 Pointcut 是否匹配目标 Bean 的类和方法</li>
	 *   <li>使用 AspectJ 表达式时，会进行运行时匹配可能性分析</li>
	 * </ul>
	 *
	 * <p>增强器扩展机制：
	 * <ul>
	 *   <li>子类可重写 extendAdvisors 方法添加特殊增强器（如 ExposeInvocationInterceptor）</li>
	 *   <li>扩展操作通常在筛选后进行，确保添加的增强器适用于所有目标 Bean</li>
	 * </ul>
	 *
	 * <p>增强器排序规则：
	 * <ul>
	 *   <li>实现 Ordered 接口的增强器按 getOrder() 返回值排序</li>
	 *   <li>未实现 Ordered 的增强器放在最后，顺序不确定</li>
	 *   <li>默认情况下，@Before 增强器按顺序执行，@After 和 @AfterReturning 按逆序执行</li>
	 * </ul>
	 *
	 * @param beanClass 待代理 Bean 的类
	 * @param beanName  当前正在处理的 Bean 名称
	 * @return 适用于该 Bean 的合格增强器列表，若没有则返回空列表（非 null）
	 *
	 * @see #findCandidateAdvisors - 获取所有候选增强器的方法
	 * @see #findAdvisorsThatCanApply - 筛选可应用增强器的方法
	 * @see #extendAdvisors - 扩展增强器列表的钩子方法
	 * @see #sortAdvisors - 对增强器进行排序的方法
	 * @see org.springframework.aop.Advisor - AOP 增强器接口
	 * @see org.springframework.aop.Pointcut - 切入点表达式接口
	 */
	protected List<Advisor> findEligibleAdvisors(Class<?> beanClass, String beanName) {
		// 1. 获取所有候选增强器（包括 BeanFactory 中定义的和注解扫描发现的）
		List<Advisor> candidateAdvisors = findCandidateAdvisors();

		// 2. 筛选出真正适用于目标 Bean 的增强器
		List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);

		// 3. 扩展增强器列表（例如添加用于暴露 AOP 调用上下文的增强器）
		extendAdvisors(eligibleAdvisors);

		// 4. 对合格增强器进行排序，确保按正确顺序执行
		if (!eligibleAdvisors.isEmpty()) {
			eligibleAdvisors = sortAdvisors(eligibleAdvisors);
		}

		return eligibleAdvisors;
	}

	/**
	 * Find all candidate Advisors to use in auto-proxying.
	 * @return the List of candidate Advisors
	 */
	protected List<Advisor> findCandidateAdvisors() {
		Assert.state(this.advisorRetrievalHelper != null, "No BeanFactoryAdvisorRetrievalHelper available");
		return this.advisorRetrievalHelper.findAdvisorBeans();
	}

	/**
	 * 从候选增强器列表中筛选出所有能够应用于指定 Bean 的增强器。
	 * 该方法负责判断每个候选增强器的切入点(Pointcut)是否匹配目标 Bean 的类或方法，
	 * 是 Spring AOP 自动代理机制中确定增强器适用性的核心环节。
	 *
	 * <p>筛选逻辑基于以下原则：
	 * <ul>
	 *   <li>对于带有 MethodMatcher 的增强器，检查其切入点是否匹配目标 Bean 的类和方法</li>
	 *   <li>支持静态匹配（基于类和方法签名）和动态匹配（基于运行时参数）</li>
	 *   <li>处理不同类型的切入点表达式（如 AspectJ 注解、正则表达式等）</li>
	 *   <li>考虑 Bean 的代理类型（JDK 动态代理或 CGLIB 代理）对匹配结果的影响</li>
	 * </ul>
	 *
	 * <p>执行流程：
	 * <ol>
	 *   <li>设置当前正在处理的 Bean 名称到上下文（用于切入点表达式中的 bean() 引用）</li>
	 *   <li>调用 AopUtils.findAdvisorsThatCanApply 执行实际筛选逻辑</li>
	 *   <li>清理上下文，确保线程安全</li>
	 * </ol>
	 *
	 * <p>上下文管理：
	 * <ul>
	 *   <li>通过 ProxyCreationContext 存储当前 Bean 名称，允许切入点表达式通过 bean() 函数引用</li>
	 *   <li>使用 try-finally 块确保上下文在方法结束后被清理，避免线程污染</li>
	 *   <li>适用于需要在切入点表达式中引用 Bean 名称的场景（如 @Pointcut("bean(myBean)")）</li>
	 * </ul>
	 *
	 * <p>性能考虑：
	 * <ul>
	 *   <li>筛选过程涉及对每个增强器的切入点表达式进行评估，可能较为耗时</li>
	 *   <li>匹配结果会被缓存，避免对同一 Bean 的重复计算</li>
	 *   <li>对于复杂的 AspectJ 表达式，可能会进行运行时匹配可能性分析</li>
	 * </ul>
	 *
	 * @param candidateAdvisors 候选增强器列表
	 * @param beanClass         目标 Bean 的类
	 * @param beanName          目标 Bean 的名称（用于切入点表达式中的 bean() 引用）
	 * @return 所有可应用于该 Bean 的增强器列表，若没有则返回空列表
	 *
	 * @see org.springframework.aop.support.AopUtils#findAdvisorsThatCanApply - 实际执行匹配逻辑的工具方法
	 * @see org.springframework.aop.Pointcut - 切入点表达式接口
	 * @see org.springframework.aop.support.MethodMatcher - 方法匹配器接口
	 * @see ProxyCreationContext - 存储代理创建上下文的工具类
	 */
	protected List<Advisor> findAdvisorsThatCanApply(
			List<Advisor> candidateAdvisors, Class<?> beanClass, String beanName) {

		// 设置当前正在处理的 Bean 名称，以便切入点表达式中可以通过 bean() 函数引用
		ProxyCreationContext.setCurrentProxiedBeanName(beanName);
		try {
			// 调用 AOP 工具类执行实际的增强器筛选逻辑
			return AopUtils.findAdvisorsThatCanApply(candidateAdvisors, beanClass);
		}
		finally {
			// 清理上下文，确保线程安全
			ProxyCreationContext.setCurrentProxiedBeanName(null);
		}
	}
	/**
	 * Return whether the Advisor bean with the given name is eligible
	 * for proxying in the first place.
	 * @param beanName the name of the Advisor bean
	 * @return whether the bean is eligible
	 */
	protected boolean isEligibleAdvisorBean(String beanName) {
		return true;
	}

	/**
	 * Sort advisors based on ordering. Subclasses may choose to override this
	 * method to customize the sorting strategy.
	 * @param advisors the source List of Advisors
	 * @return the sorted List of Advisors
	 * @see org.springframework.core.Ordered
	 * @see org.springframework.core.annotation.Order
	 * @see org.springframework.core.annotation.AnnotationAwareOrderComparator
	 */
	protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
		AnnotationAwareOrderComparator.sort(advisors);
		return advisors;
	}

	/**
	 * Extension hook that subclasses can override to register additional Advisors,
	 * given the sorted Advisors obtained to date.
	 * <p>The default implementation is empty.
	 * <p>Typically used to add Advisors that expose contextual information
	 * required by some of the later advisors.
	 * @param candidateAdvisors the Advisors that have already been identified as
	 * applying to a given bean
	 */
	protected void extendAdvisors(List<Advisor> candidateAdvisors) {
	}

	/**
	 * This auto-proxy creator always returns pre-filtered Advisors.
	 */
	@Override
	protected boolean advisorsPreFiltered() {
		return true;
	}


	/**
	 * Subclass of BeanFactoryAdvisorRetrievalHelper that delegates to
	 * surrounding AbstractAdvisorAutoProxyCreator facilities.
	 */
	private class BeanFactoryAdvisorRetrievalHelperAdapter extends BeanFactoryAdvisorRetrievalHelper {

		public BeanFactoryAdvisorRetrievalHelperAdapter(ConfigurableListableBeanFactory beanFactory) {
			super(beanFactory);
		}

		@Override
		protected boolean isEligibleBean(String beanName) {
			return AbstractAdvisorAutoProxyCreator.this.isEligibleAdvisorBean(beanName);
		}
	}

}
